/**
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *    
 *    Linking this library statically or dynamically with other modules 
 *    is making a combined work based on this library. Thus, the terms and
 *    conditions of the GNU General Public License cover the whole
 *    combination.
 *    
 *    As a special exception, the copyright holders of this library give 
 *    you permission to link this library with independent modules to 
 *    produce an executable, regardless of the license terms of these 
 *    independent modules, and to copy and distribute the resulting 
 *    executable under terms of your choice, provided that you also meet, 
 *    for each linked independent module, the terms and conditions of the 
 *    license of that module.  An independent module is a module which 
 *    is not derived from or based on this library.  If you modify this 
 *    library, you may extend this exception to your version of the 
 *    library, but you are not obligated to do so.  If you do not wish 
 *    to do so, delete this exception statement from your version.
 *
 *    Project: Financas Pessoais
 *    Author : Igor Salles
 */
package org.fp.logger;

import java.io.IOException;
import java.net.URL;
import java.util.Properties;
import java.util.logging.ConsoleHandler;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

/**
 * Simple wrapper for jdk logging system. The objective to this wrapper its to
 * keep all the configurations and setting on one place for all the project.
 * Also theres a exemple to override the xmlformater methods.
 *  
 * @author Igor Salles
 * @version 0.01
 * @since May 18, 2011
 * 
 */
public class Jornal {

    /* the default logger for the entire system */
    private static java.util.logging.Logger jornal = null; //java.util.logging.Logger.getLogger(Jornal.class.getName());
    /* the default file size for the logger files. */
    private static final int FILE_SIZE = 1024 * 1024;

    /**
     * Constructor for the class. This constructor main activite is to create
     * the logger object and set its handlers. For debug and manutence will be
     * only one logger instance for the entire project.
     */
    private Jornal() {
        //cria um novo logger com o nome da raiz do projecto
        jornal = java.util.logging.Logger.getLogger("org.fp");
        //desativa o loggers handlers do logger pai (por default um consolehandler).
        jornal.setUseParentHandlers(false);
        //chama config para configurar os handlers, formaters e os leveis
        this.configure();
    }

    /**
     * Configure logger with the project defaults from propertie file. For now
     * the follow will be done:
     * <dl>
     * <dt>loading the default properties file inside this project;</dt>
     * <dt>create the especified handlers;</dt>
     * <dt>create a filehandler with a simpleformate;</dt>
     * <dt>set the proper level for all handlers.</dt>
     * </dl>
     */
    private void configure() {
        //remove default handlers
//        Logger globalLogger = Logger.getLogger("");
//        Handler[] handlers = globalLogger.getHandlers();
//        for (Handler handler : handlers){
//            globalLogger.removeHandler(handler);
//        }
        //try to disable the global handler and logger
        //jornal.setUseParentHandlers(true);
        //System.out.println(""+jornal.getUseParentHandlers());
        //jornal.setUseParentHandlers(false);
        //System.out.println(""+jornal.getUseParentHandlers());        

        //       jornal = Logger.getLogger(this.getClass().getName());
        Properties prop = new Properties();
        //get the real path for the config file into the jar of the project
        URL propsPath =
                ClassLoader.getSystemResource("org/fp/files/logging.properties");
        //if we try to load the path with a FileInputStream and the path for 
        //the config file inside the jar, it raises a exception.
        if (propsPath != null) {
            try {
                //load props from the file.
                prop.load(propsPath.openStream());
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        } else { //caminho para o arquivo nao existe logo...
            //TODO: se nao encontrar o arquivo de props tenho de criar um novo
            //com as definicoes padroes do sistema. 
            //É possivel criar props dentro de um jar em run time???
        }
        //prop.list(System.out);
        //vamos verificar os handlers
        String propHdlers = prop.getProperty("handlers");
        //vamos ter de passar por cada uma das possibilidades de LEVELs para os
        //handlers algo como (ja que strings nao podem entrar em um switch)
        String propLvl = prop.getProperty(".level");
        if (propHdlers.contains("ConsoleHandler")) {
            ConsoleHandler ch = new ConsoleHandler();
            ch.setLevel(this.configLevels(prop));//seta o lvl para o consolehandler
            ch.setFormatter(new SimpleFormatter()); //formatador do consolehandler
            try {
                jornal.addHandler(ch); //adiciona o consolehandler ao logger;
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("" + jornal.getParent());
                System.out.println("" + jornal.getHandlers());
            }
            if (propHdlers.contains("FileHandler")) {
                try {
                    //novo file handler: ate 2 arquivos com o tamanho de
                    //FILE_SIZE (1mb), com rolling name e anexando (append)
                    //ao final do arquivo.
                    FileHandler fh = new FileHandler(
                            "fp_%g.xml", //arquivo de log 
                            FILE_SIZE, //tamanho max do arquivo de log
                            1, //numero de arquivos de log
                            true); // ativa append ao arquivo
                    fh.setLevel(this.configLevels(prop)); //seta o lvl para msg
                    FileHandler fh2 = new FileHandler("fp.log", FILE_SIZE, 1, true);
                    fh2.setFormatter(new SimpleFormatter());
                    jornal.addHandler(fh);
                    jornal.addHandler(fh2);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } else { //nao achamos nada util dentro do campo entao
            ConsoleHandler ch = new ConsoleHandler();
            ch.setFormatter(new SimpleFormatter());
            ch.setLevel(this.configLevels(prop));
            //jornal.addHandler(ch);
        }
        //o logger tbm precisa ter seu lvl setado se nao nao filtrara as mensagens
        //para a console. 
        jornal.setLevel(this.configLevels(prop));
    }
//
//    private void createHandlers(Properties props) {
//        //cria os handlers de acordo com as configuracoes do 
//        //arquivo de properties
//    }

    /**
     * Receive a prop file and search for a <code>.level</code> tag and 
     * returns the level setting.
     * 
     * @param props A properties file with logging settings.
     * @return level for the handler
     */
    private Level configLevels(Properties props) {
        String propLvl = props.getProperty(".level");
        Level retorno = null;
        try {
            return Level.parse(propLvl);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
            if (propLvl.equalsIgnoreCase("ALL")) {
                return Level.ALL;
            } else if (propLvl.equalsIgnoreCase("CONFIG")) {
                return Level.CONFIG;
            } else if (propLvl.equalsIgnoreCase("FINE")) {
                return Level.FINE;
            } else if (propLvl.equalsIgnoreCase("ALL")) {
                return Level.FINER;
            } else if (propLvl.equalsIgnoreCase("ALL")) {
                return Level.FINEST;
            } else if (propLvl.equalsIgnoreCase("ALL")) {
                return Level.INFO;
            } else if (propLvl.equalsIgnoreCase("ALL")) {
                return Level.SEVERE;
            } else if (propLvl.equalsIgnoreCase("ALL")) {
                return Level.WARNING;
            } else if (propLvl.equalsIgnoreCase("ALL")) {
                return Level.OFF;
            } else if (propLvl.equalsIgnoreCase("ALL")) {
                return Level.OFF;
            } else {
                return Level.SEVERE;
            }
        }
    }

    public static synchronized Logger getInstance() {
        if (jornal == null) {
            Jornal lg = new Jornal();
//            //adicionar um novo filehandler e tentar dar override no getHead
//            //do XMLFormater. Este eh so um showcase para ver como seria possivel
//            //dar override nos headers and tail de um xml loger.
//            try {
//                FileHandler fh2 = new FileHandler("fp.log", true);
//                fh2.setFormatter(new XMLFormatter() {
//                    @Override
//                    public String getHead(Handler h) {
//                        StringBuffer sb = new StringBuffer();
//                        String encoding;
//                        //sb.append("<!--\n");
//                        sb.append("<!-- ");
//                        sb.append("<?xml version=\"1.0\"");
//
//                        if (h != null) {
//                            encoding = h.getEncoding();
//                        } else {
//                            encoding = null;
//                        }
//
//                        if (encoding == null) {
//                            // Figure out the default encoding.
//                            encoding = sun.io.Converters.getDefaultEncodingName();
//                        }
//                        // Try to map the encoding name to a canonical name.
//                        try {
//                            Charset cs = Charset.forName(encoding);
//                            encoding = cs.name();
//                        } catch (Exception ex) {
//                            // We hit problems finding a canonical name.
//                            // Just use the raw encoding name.
//                        }
//
//                        sb.append(" encoding=\"");
//                        sb.append(encoding);
//                        sb.append("\"");
//                        sb.append(" standalone=\"no\"?>\n");
//                        //sb.append("<!DOCTYPE log SYSTEM \"logger.dtd\">\n");
//                        sb.append("<!DOCTYPE log SYSTEM \"logger.dtd\">");
//                        sb.append("<log>\n");
//                        sb.append("  -->\n");
//                        return sb.toString();
//                    }
//
//                    @Override
//                    public String getTail(Handler h) {
//                        return "<!-- </log> -->\n";
//
//                    }
//                });
//                jornal.addHandler(fh2);
//            } catch (IOException e) {
//                e.printStackTrace();
//            }

            return jornal;
        }
        return jornal;
    }
}
